取消操作的原因:
- 用户请求取消
- 有时间限制的操作
- 应用程序事件
- 错误
- 关闭
任务中断的三种方式:
使用请求关闭标记(例如boolean开关)
成功的例子:
|
|
Test
|
|
失败的例子:
|
|
Test
|
|
使用中断机制
与中断相关的
|
|
InterruptedException异常:
针对上面的BlockingQueue的put方法是阻塞的,但是线程会检检测到中断的发生,并抛出InterruptedException,来提早结束任务。避免了阻塞导致线程一直等待的情况发生。
实例:
|
|
通过Future来实现取消
|
|
响应中断
阻塞库方法,例如Thread.sleep和Object.wait等,都会检杏线程何时中断,并且在发现中断时提前返回。它们在响应中断时执行的操作包括:
1.清除中断状态
2.抛出InterruptedException
表示阻塞操作由于中断而提前结束。JVM并不能保证阻塞方法检测到中断的速度,但在实际情况中响应速度还是非常快的。
响应中断的方法
1.传递异常(throws InterruptedException)
2.恢复中断状态,从而事调用栈的上层代码能够对其进行处理(Thread.currentThread().interrupt();)
例子:
|
|
处理不可中断的阻塞
Java.io包中的同步Socket I/O。虽然InputStream和OutputStream中的read和write等方法都不会响应中断,但通过关闭底层的套接字,可以使得由于执行read或write等方法而被阻塞的线程抛出一个SocketException。
Java.io包中的同步I/O。当中断一个正在InterruptibleChannel上等待的线程时,将抛出ClosedByInterruptedException)并关闭链路(这还会使得其他在这条链路上阻塞的线程同样抛出ClosedByInterruptException)。当关闭一个InterruptibleChannel时,将导致所有在链路操作上阻塞的线程抛出AsynchronousCloseException。大多数标准的Channel都实现了InterruptibleChannel。
Selector的异步I/O。如果一个线程在调用Selector.select方法(在java.nio.channels中)时阻塞了,那么调用close或wakeup方法会使线程抛出ClosedSelectorException并提前返回。
获取某个锁。如果一个线程由于等待某个内置锁而被阻塞,那么将无法响应中断,因为线程认为它肯定获得锁,所以将不会理会中断请求。但是,在Lock类中提供了lockInterruptibly方法,该方法允许在等待一个锁的同时仍能响应中断。
采用newTaskFor来封装非标准的取消
停止基于线程的服务
日志服务示例
|
|
关闭ExecutorService
shutdown():启动一次顺序关闭,执行完以前提交的任务,没有执行完的任务继续执行完。
shutdownNow():试图停止所有正在执行的任务(向它们发出interrupt操作语法,无法保证能够停止正在处理的任务线程,但是会尽力尝试),并暂停处理正在等待的任务,并返回等待执行的任务列表。
ExecutorService已关闭,再向它提交任务时会抛RejectedExecutionException异常
只要调用了这两个关闭方法中的任意一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。
至于应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。
“毒丸”对象——当得到这个对象时,立即停止
在提交“毒丸”对象之前提交的所有工作都会被处理,而生产者在提交了“毒丸”对象后,将不会再提交任何工作
只执行一次的服务
如果某个方法需要处理一批任务,并且当所有任务都处理完成后才返回,那么可以通过一次私有的Executor来简化服务的生命周期管理,其中该Executor的生命周期是由这个方法来控制的。
处理非正常的线程终止
在一个线程中启动另一个线程,另一个线程中抛出异常,如果没有捕获它,这个异常也不会传递到父线程中
任何代码都可能抛出一个RuntimeException。每当调用另一个方法时,都要对它的行为保持怀疑,不要盲目地认为它一定会正常返回,或者一定会抛出在方法原型中声明的某个已检查异常
未捕获异常的处理
|
|
jvm关闭
JVM的关闭意味着将停止系统中所有的任务,可以由其自动关闭也可以主动触发。
关闭钩子
如果我们想在JVM关闭时做一些事情该怎么办?JVM提供给开发者提供了关闭钩子,使其在JVM关闭时可以利用一个线程来做一些收尾工作例如(删除临时文件)。注册关闭钩子的方法是调用Runtime.addShutdownHook
守护线程 一个线程来执行一些辅助工作,但有不希望这个线程阻碍JVM的关闭
守护线程用于执行一些辅助任务,如垃圾回收,JVM关闭时不论守护线程运行到哪里都可能马上停止。
终结器(清理文件句柄或套接字句柄等)——避免使用
垃圾回收器对那些定义了finalize方法的对象会进行特殊处理:在回收器释放它们后,调用它们的finalize方法,从而确保一些持久化的资源被释放。
通过使用finally代码块和显式的close方法,能够比使用终结器更好地管理资源
例外:当需要管理对象时,并且该对象持有的资源是通过本地方法获得的